#include "wifi.h"
#include "disp.h"
#include "bs818.h"
#include "task.h"
#include "bitmap.h"
#include "WiFiManager.h"
#include "ESP8266WiFiMulti.h"
#include "EEPROM.h"

uint8_t WIFI_STATE  = 0;
uint8_t smart_config = 0;
extern uint8_t force_request;
extern uint8_t font_color[3];
String wifi_ssid;
String wifi_pwd;
uint8_t normal_bright = 0;
char weather_key[20];
char weather_city[20];
ESP8266WebServer httpServer(80);
ESP8266HTTPUpdateServer httpUpdater;
WiFiManager wm;
ESP8266WiFiMulti wifi_multi;
WiFiManagerParameter set_key("key", "Key", NULL, 20);
WiFiManagerParameter set_city("city", "City", NULL, 20);
WiFiManagerParameter set_red("red", "RED", NULL, 3);
WiFiManagerParameter set_green("green", "GREEN", NULL, 3);
WiFiManagerParameter set_blue("blue", "BLUE", NULL, 3);
WiFiManagerParameter set_bright("brightness", "BRIGHTNESS", NULL, 3);

void wifiDisp(uint8_t state)
{
    static uint8_t n1 = 0, n2 = 0;

    dispClear();
    setColor(0, 50, 100);
    drawChar('W', 4, 2, 5);
    drawChar('i', 10, 2, 5);
    drawChar('F', 12, 2, 5);
    drawChar('i', 16, 2, 5);
    if(state == WIFI_NOT_CONNECT)      //disconnect
    {
        setColor(100 , 0, 0);
        drawChar('X', 19, 2, 5);
    }
    else if(state == WIFI_CONNECTING)     //connecting
    {
        setColor(0, 50, 100);
        // switch (n2)
        // {
        // case 0:
        //     drawPoint(19, 6, 1);
        //     n2++;
        //     break;
        // case 1:
        //     drawPoint(19, 6, 1);
        //     drawPoint(20, 6, 1);
        //     n2++;
        //     break;
        // case 2:
        //     drawPoint(19, 6, 1);
        //     drawPoint(20, 6, 1);
        //     drawPoint(21, 6, 1);
        //     n2++;
        //     break;
        // case 3:
        //     drawPoint(19, 6, 1);
        //     drawPoint(20, 6, 1);
        //     drawPoint(21, 6, 1);
        //     drawPoint(22, 6, 1);
        //     n2++;
        //     break;
        // case 4:
            drawPoint(19, 6, 1);
            drawPoint(20, 6, 1);
            drawPoint(21, 6, 1);
            drawPoint(22, 6, 1);
            drawPoint(23, 6, 1);
            // n2 = 0;
        //     break;
        // default:
        //     break;
        // }
    }
    else if(state == WIFI_CONNECTED)       //connected
    {
        setColor(0, 100, 50);
        switch (n2)
        {
        case 0:
            drawPoint(19, 4, 1);
            n2++;
            break;
        case 1:
            drawPoint(19, 4, 1);
            drawPoint(20, 5, 1);
            n2++;
            break;
        case 2:
            drawPoint(19, 4, 1);
            drawPoint(20, 5, 1);
            drawPoint(21, 6, 1);
            n2++;
            break;
        case 3:
            drawPoint(19, 4, 1);
            drawPoint(20, 5, 1);
            drawPoint(21, 6, 1);
            drawPoint(22, 5, 1);
            n2++;
            break;
        case 4:
            drawPoint(19, 4, 1);
            drawPoint(20, 5, 1);
            drawPoint(21, 6, 1);
            drawPoint(22, 5, 1);
            drawPoint(23, 4, 1);
            n2++;
            break;
        case 5:
            drawPoint(19, 4, 1);
            drawPoint(20, 5, 1);
            drawPoint(21, 6, 1);
            drawPoint(22, 5, 1);
            drawPoint(23, 4, 1);
            drawPoint(24, 3, 1);
            n2++;
            break;
        case 6:
            drawPoint(19, 4, 1);
            drawPoint(20, 5, 1);
            drawPoint(21, 6, 1);
            drawPoint(22, 5, 1);
            drawPoint(23, 4, 1);
            drawPoint(24, 3, 1);
            drawPoint(25, 2, 1);
            n2 = 0;
            break;
        default:
            break;
        }
    }
}

void smartConfig(void)
{
    static uint8_t cnt = 0;
    smart_config = 1;
    wifiDisp(WIFI_CONNECTING);
    disp();
    WiFi.beginSmartConfig();
    while(1)
    {
        Serial.print(">");
        touchScan();
        delay(100);
        // if(cnt == 5)
        // {
        //     wifiDisp(WIFI_CONNECTING);
        //     cnt = 0;
        // }
        // cnt++;
        if(WiFi.smartConfigDone())
        {
            cnt = 7;
            while(cnt--)
            {
                wifiDisp(WIFI_CONNECTED);
                disp();
                delay(70);
            }
            // WiFi.stopSmartConfig();
            Serial.println("Smartconfig success");
            Serial.printf("SSID:%s", WiFi.SSID().c_str());
            Serial.printf("PSD:%s", WiFi.psk().c_str());
            delay(1000);
            break;
        }
        if(key_status == KEY_MENU)
        {
            wifiDisp(WIFI_NOT_CONNECT);
            disp();
            delay(1000);
            break;
        }
    }
}

void wifiCheckTask(void)
{
    if(WiFi.status() == WL_CONNECTED)
    {
        WIFI_STATE = 1;
    }
    else
    {
        WIFI_STATE = 0;
    }
}

void eepromWriteStr(char *s, uint8_t len, uint16_t addr)
{
    uint8_t i = 0;

    if(len != 0)
        len+=1;
    EEPROM.write(addr, len);
    for(i=0, addr+=1; i<len; i++, addr++)
    {
        EEPROM.write(addr, s[i]);
    }
    EEPROM.commit();
    Serial.printf("%s stored, len:%d\r\n", s, len);
}

/*save config to EEPROM*/
void saveConfig(void)
{
    uint8_t len = 0, i = 0;
    uint16_t addr = 0;

    wifi_ssid = wm.getWiFiSSID();
    len = wifi_ssid.length();
    eepromWriteStr((char*)wifi_ssid.c_str(), len, addr);
    // Serial.printf("ssid:%s stored, len:%d\r\n", wifi_ssid, len);
    addr = addr + len + 2;

    wifi_pwd = wm.getWiFiPass();
    len = wifi_pwd.length();
    eepromWriteStr((char*)wifi_pwd.c_str(), len, addr);
    // Serial.printf("password:%s stored, len:%d\r\n", wifi_pwd, len);
    addr = addr + len + 2;

    strcpy(weather_key, set_key.getValue());
    len = strlen(weather_key);
    eepromWriteStr(weather_key, len ,addr);
    // Serial.printf("appid:%s stored, len:%d\r\n", weather_appid, len);
    addr = addr + len + 2;

    strcpy(weather_city, set_city.getValue());
    len = strlen(weather_city);
    eepromWriteStr(weather_city, len ,addr);
    // Serial.printf("city:%s stored, len:%d\r\n", weather_city, len);
    addr = addr + len + 2;

    // strcpy(color, set_red.getValue());
    font_color[0] = atoi(set_red.getValue());
    EEPROM.write(addr, font_color[0]);
    addr = addr + 1;

    font_color[1] = atoi(set_green.getValue());
    EEPROM.write(addr, font_color[1]);
    addr = addr + 1;

    font_color[2] = atoi(set_blue.getValue());
    EEPROM.write(addr, font_color[2]);
    addr += 1;

    normal_bright = atoi(set_bright.getValue());
    EEPROM.write(addr, normal_bright);

    EEPROM.end();

    setBrightness((float)normal_bright/100.0);
    force_request = 1;
}

uint8_t eepromReadStr(char *s, uint16_t addr)
{
    uint8_t i = 0, len = 0;

    len = EEPROM.read(addr);
    for(i=0, addr+=1; i<len; i++, addr++)
    {
        s[i] = EEPROM.read(addr);
        if(i != len-1)
        {
            if(s[i]<33 || s[i]>126)
            {
                len = 0;
                break;
            }
        }
    }
    return len;
}

/*read config from EEPROM*/
void readConfig(void)
{
    uint8_t str_err = 0;
    uint8_t len = 0, i = 0;
    uint16_t addr = 0;
    char setting[20];

    Serial.println("read config...");

    memset(setting, 0, 20);
    len = eepromReadStr(setting, addr);
    if(len != 0)
        wifi_ssid = (String)setting;
    Serial.printf("ssid:%s\r\n", wifi_ssid);
    addr = addr + len + 1;

    memset(setting, 0, 20);
    len = eepromReadStr(setting, addr);
    if(len != 0)
        wifi_pwd = (String)setting;
    Serial.printf("pwd:%s\r\n", wifi_pwd);
    addr = addr + len +1;

    memset(setting, 0, 20);
    len = eepromReadStr(setting, addr);
    if(len != 0)
        strcpy(weather_key, setting);
    Serial.printf("appid:%s\r\n", weather_key);
    addr = addr + len +1;

    memset(setting, 0, 20);
    len = eepromReadStr(setting, addr);
    if(len != 0)
        // strcpy(weather_city, setting);
        memcpy(weather_city, setting, len);
    Serial.printf("city:%s\r\n", weather_city);
    addr = addr + len +1;

    font_color[0] = EEPROM.read(addr);
    Serial.printf("red:%d\r\n", font_color[0]);
    addr += 1;

    font_color[1] = EEPROM.read(addr);
    Serial.printf("green:%d\r\n", font_color[1]);
    addr += 1;

    font_color[2] = EEPROM.read(addr);
    Serial.printf("blue:%d\r\n", font_color[2]);
    addr += 1;

    normal_bright = EEPROM.read(addr);

    setBrightness((float)normal_bright/100.0);
    Serial.printf("brightness:%f\r\n", (float)normal_bright/100.0);
}

void initWiFi(void)
{
    EEPROM.begin(512);
    wm.setShowPassword(true);
    wm.setBreakAfterConfig(true);
    wm.setSaveConfigCallback(saveConfig);
    wm.setDebugOutput(false);
    wm.setWiFiAutoReconnect(true);
    wm.addParameter(&set_key);
    wm.addParameter(&set_city);
    wm.addParameter(&set_red);
    wm.addParameter(&set_green);
    wm.addParameter(&set_blue);
    wm.addParameter(&set_bright);

    readConfig();
    WiFi.mode(WIFI_STA);
    WiFi.begin(wifi_ssid, wifi_pwd);
}

void webConfig(void)
{
    static uint8_t web_flag = 0;
    uint8_t cnt = 0;
    char color[4] = {0, 0, 0, 0};

    if(key_status == KEY_M_L || web_flag == 1)
    {
        key_status = KEY_NONE;
        // wm.disconnect();
        taskStop();
        wifiDisp(WIFI_CONNECTING);
        disp();
        set_key.setValue(weather_key, 20);
        set_city.setValue(weather_city, 20);
        sprintf(color, "%d", font_color[0]);
        set_red.setValue(color, 3);
        sprintf(color, "%d", font_color[1]);
        set_green.setValue(color, 3);
        sprintf(color, "%d", font_color[2]);
        set_blue.setValue(color, 3);
        sprintf(color, "%d", normal_bright);
        set_bright.setValue(color, 3);
        wm.startConfigPortal("PixelClock", "12345678");
        web_flag = 0;
        cnt = 7;
        while(cnt--)
        {
            wifiDisp(WIFI_CONNECTED);
            disp();
            delay(70);
        }
        delay(1000);
        taskStart();
    }
}

void updateDisp(void)
{
    uint8_t i = 0;
    static uint8_t cnt = 0, y = 0;
    dispClear();
    if(cnt == 20)
    {
        cnt = 0;
        y++;
        if(y == 8)
            y = -7;
    }
    drawBitmapRGB(upload, 12, y, 7, 7);
    setColor(0, 50, 100);
    for(i=0; i<8; i++)
        drawPoint(12+i, 7, 1);
    disp();
    cnt++;
}

uint8_t firmware_run = 0;
void firmwareUpdate(void)
{
    static uint8_t cnt = 0;
    if(WIFI_STATE)
    {
        if(key_status == KEY_R_L || cnt == 1)
        {
            if(cnt == 0)
            {
                cnt = 1;
                taskStop();
                firmware_run = 1;
                MDNS.begin("pixelclock");
                httpUpdater.setup(&httpServer);
                httpServer.begin();
                MDNS.addService("http", "tcp", 80);
            }
            else
            {                
                if(key_status == KEY_MENU)
                {
                    taskStart();
                    cnt = 0;
                    firmware_run = 0;
                    return;
                }
                updateDisp();
                httpServer.handleClient();
                MDNS.update();
            }
        }
    }
}
